﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NLite.Collections;
using NLite.Reflection;

namespace NLite.Internal
{
    static class MetadataService
    {
        public static PropertySet GetMappings(this Type type)
        {
            var metadata = new PropertySet() as IDictionary<string,object>;

            var items = (from item in type.GetCustomAttributes(false)
                      let p = item as IMetadata
                      where p != null
                      group p by p.Name into g
                      select new { Name = g.Key, g }
                     ).ToList();

            var otherItems = (from item in type.GetCustomAttributes(false)
                              let itemType = item.GetType()
                              where itemType.HasAttribute<MetadataAttributeAttribute>(true)
                              group item by itemType into g
                              select g).ToList();

            foreach (var item in otherItems)
            {
                var group = item.ToList();

                var props = (from p in item.Key.GetProperties()
                             where !(p.Name == "TypeId" && p.PropertyType == typeof(object))
                            select new { Name = p.Name, Handler = p.GetGetMethod(),Result = new List<object>() }).ToList();

                var fields = (from p in item.Key.GetFields()
                              select new { Name = p.Name, Field = p, Result = new List<object>() }).ToList();

                foreach (var i in group)
                {
                    foreach (var p in props)
                        p.Result.Add(p.Handler.FastFuncInvoke(i, new object[0]));

                    foreach (var p in fields)
                        p.Result.Add(p.Field.Get(i));
                }

                foreach (var p in props)
                {
                    if (p.Result.Count == 1)
                        metadata.Add(p.Name, p.Result[0]);
                    else if (p.Result.Count > 1)
                    {
                        try
                        {
                            metadata.Add(p.Name, p.Result.ToArray());
                        }
                        catch
                        {
                            Console.WriteLine(p.Name);
                        }
                            
                    }
                }

                foreach (var p in fields)
                {
                    if (p.Result.Count == 1)
                        metadata.Add(p.Name, p.Result[0]);
                    else if (p.Result.Count > 1)
                        metadata.Add(p.Name, p.Result.ToArray());
                }
               
            }


            foreach (var item in items)
            {
                var vals = item.g.ConvertAll<IMetadata, object>(p => p.Value).ToArray();
                if (vals.Length > 1)
                    metadata.Add(item.Name, vals);
                else if (vals.Length == 1)
                    metadata.Add(item.Name, vals[0]);
            }

            return metadata as PropertySet;
        }
    }
}
